#!/usr/bin/perl

# $Id: PoxParser.pm 154 2009-02-02 23:27:51Z mail@tobyinkster.co.uk $

######################################################################
package Swignition::PoxParser;
######################################################################

use Swignition::MagicString;
use XML::LibXML;
use XML::LibXSLT;
use utf8;
use strict;

use Swignition::GenericParser;
use vars qw(@ISA);
@ISA = qw(Swignition::GenericParser);

sub new
{
	my $class    = shift;
	my $source   = shift;
	my $opts     = shift;
	my $this     = Swignition::GenericParser::object_structure($source, $opts);
	
	bless $this, $class;	
	
	$this->build_dom_tree;
	$this->find_base_uri;
	
	if ($this->{options}->{p_AUTO})
	{
		$this->{RDF}->{ $this->uri } = Swignition::RDFModel::Subject->new($this->uri);	

		if ($this->{DOM}->documentElement->tagName eq 'TriX')
		{
			$this->handle_trix;
		}
		
		else
		{
			Swignition::GenericParser::GRDDL::consume($this)
				if Swignition::GenericParser::GRDDL::is_enabled($this);
		}
		
		Swignition::GenericParser::HTTP::consume($this)
			if Swignition::GenericParser::HTTP::is_enabled($this);

		Swignition::GenericParser::Recursive::consume($this)
			if Swignition::GenericParser::HTTP::is_enabled($this);

		$this->smush;
	}

	return $this;	
}

sub build_dom_tree
{
	my $this = shift;

	# XML::LibXML parser.
	$Swignition::GenericParser::XDP = XML::LibXML->new();
	
	# Attempt to parse.
	eval {
		$this->{DOM} = $Swignition::GenericParser::XDP->parse_string($this->{Source});
	};
	
	# If parsing failed, then 
	if (! $this->{DOM} )
	{
		$this->{_raw_source} = $this->{Source};
		
		# Figure out encoding.
		my $enc = 'iso-8859-1';
		if (($this->{RESPONSE} && $this->{RESPONSE}->header('content-type') =~ /\bcharset=[\"\'\s]?([a-z0-9-]+)/i)
		|| substr($this->{Source},0,2048) =~ /\bencoding=[\"\'\s]?([a-z0-9-]+)/i 
		|| substr($this->{Source},0,2048) =~ /\bcharset=[\"\'\s]?([a-z0-9-]+)/i )
			{ $enc = lc($1); }
		
		# Decode into UTF-8.
		if ($enc ne 'utf-8')
		{
			$this->{decoded_from} = $enc;
			$this->{Source} = decode($enc, $this->{Source});
		}

		# Try parsing again.
		if (!eval {
			$this->{DOM} = $Swignition::GenericParser::XDP->parse_string($this->{Source});
		})
		
		# If it still fails, then
		{
			print "COULD NOT PARSE!\n";
			die;
		}
	}	
}


sub handle_trix
{
	my $this = shift;
	my $rdf  = shift || $this->{'Source'};
	my $base = shift || $this->{'RESPONSE'}->base;
	my $DOM  = shift || $this->{'DOM'};
	
	my $XMLParser = XML::LibXML->new();

	unless ($DOM)
		{ $DOM = $XMLParser->parse_string($rdf); }
	
	# XSLT stuff
	foreach my $pi ( $DOM->findnodes('//processing-instruction()') )
	{
		next unless lc($pi->nodeName) eq  "xml-stylesheet";
		if ($pi->getData =~ /href="([^"]+)"/i)
		{
			my $uri = URI->new( $this->uri($1) );
			next if ($this->{NoFollow}->{ $uri->host });

			my $request  = HTTP::Request->new(GET => "$uri");
			$request->header('Accept', 'application/xslt+xml, '
			                         . 'text/xslt, '
			                         . 'text/xsl'
			                         . 'application/xml, '
			                         . 'text/xml');
			my $response = $this->get_ua->request($request);

			if ($response->header('content-type') =~ /(xsl|xml)/i)
			{
				my $xslt       = XML::LibXSLT->new();
				my $style_doc  = $XMLParser->parse_string($response->content);
	
				my $stylesheet;
				eval { $stylesheet = $xslt->parse_stylesheet($style_doc); };
								
				unless ($@)
				{
					my $results = $stylesheet->transform($DOM);
					$DOM = $results if ($results);
				}
			}
		}
	}
	
	my $default_graph = $this->graph;

	my $graphCount = 0;

	GRAPH: foreach my $graph ($DOM->documentElement->getChildrenByTagNameNS('http://www.w3.org/2004/03/trix/trix-1/', 'graph'))	
	{
		$graphCount++;
		
		my $graphURI = undef;
		{
			my @uris  = $graph->getChildrenByTagNameNS('http://www.w3.org/2004/03/trix/trix-1/', 'uri');
			$graphURI = $uris[0]->textContent if (@uris);
			$graphURI = sprintf("TriX%02d", $graphCount) unless ($graphURI);
		}
		
		my $current_graph = $this->graph($graphURI);
		
		TRIPLE: foreach my $triple ($graph->getChildrenByTagNameNS('http://www.w3.org/2004/03/trix/trix-1/', 'triple'))
		{
			my @components = $triple->getChildrenByTagName('*');
			
			next if defined $components[3]; # Only [0] to [2] should be defined.
			next unless defined $components[2]; # But [0] to [2] must be defined!

# Allow non-RDF graphs			
#			next unless $components[0]->tagName =~ /^(id|uri)$/; 
#			next unless $components[1]->tagName eq 'uri';
#			next unless $components[2]->tagName =~ /^(id|uri|plainLiteral|typedLiteral)$/; 
			
			my @nodes;
			
			NODE: for (my $i=0 ; $i<3; $i++)
			{
				if ($components[$i]->tagName eq 'uri')
				{
					$nodes[$i] = $current_graph->lookup_node($components[$i]->textContent, 1);
				}
				elsif ($components[$i]->tagName eq 'id')
				{
					$nodes[$i] = $current_graph->lookup_node('_:'.$components[$i]->textContent, 1);
				}
				elsif ($components[$i]->tagName eq 'plainLiteral')
				{
					my $ms = $components[$i]->textContent;
					if ($components[$i]->getAttribute('xml:lang'))
						{ $ms = strlang($ms, $components[$i]->getAttribute('xml:lang')); }
					$nodes[$i] = Swignition::DataModel::Literal->new($this->model, $ms);
				}
				elsif ($components[$i]->tagName eq 'typedLiteral')
				{
					if ($components[$i]->getAttribute('datatype') eq 'http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral'
					&&  $components[$i]->getElementsByTagName('*'))
					{
						my $xml = '';
						foreach my $kid ($components[$i]->childNodes)
							{ $xml .= $kid->toStringC14N; }
						$nodes[$i] = Swignition::DataModel::Literal->new($this->model, $xml);
					}
					else
					{
						$nodes[$i] = Swignition::DataModel::Literal->new($this->model, $components[$i]->textContent);
					}
					$nodes[$i]->set_datatype($components[$i]->getAttribute('datatype'));
				}
				else
				{
					next TRIPLE;
				}
			}
			
			next TRIPLE unless ($nodes[0] && $nodes[1] && $nodes[2]);
			
			my $triple = $current_graph->quick(@nodes);
#			$default_graph->add_triple($triple);
		}
	}
}



1;
